/*
 * Copyright (C) 2012, EADS France
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

package xowl.utils.config;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 *
 * @author Laurent WOUTERS
 */
public class Configuration {
    private Section global;
    private Map<String, Section> sections;

    public Section getGlobalSection() { return global; }
    public Section getSection(String name) {
        if (name == null)
            return global;
        if (!sections.containsKey(name))
            sections.put(name, new Section(name));
        return sections.get(name);
    }
    
    public List<String> getValues(String property) { return global.getValues(property); }
    public String getValue(String property) { return global.getValue(property); }
    public List<String> getValues(String section, String property) {
        if (section == null)
            return global.getValues(property);
        Section current = sections.get(section);
        if (current == null)
            return new LinkedList<String>();
        return current.getValues(property);
    }
    public String getValue(String section, String property) {
        if (section == null)
            return global.getValue(property);
        Section current = sections.get(section);
        if (current == null)
            return null;
        return current.getValue(property);
    }
    public void addValue(String section, String property, String value) {
        getSection(section).addValue(property, value);
    }
    
    public Configuration() {
        global = new Section(null);
        sections = new HashMap<String, Section>();
    }
    
    public void save(String file, Charset charset) throws IOException  {
        FileOutputStream stream = new FileOutputStream(file);
        OutputStreamWriter writer = new OutputStreamWriter(stream, charset);
        try {
            global.save(writer);
            boolean before = !global.isEmpty();
            for (Section section : sections.values()) {
                if (before)
                    writer.write(System.lineSeparator());
                section.save(writer);
                before = (before || !section.isEmpty());
            }
        }
        finally { writer.close(); }
    }
    
    public void load(InputStream stream, Charset charset) throws IOException {
        String content = xowl.utils.Files.read(stream, charset);
        String[] lines = content.split("\r\n");
        Section current = global;
        for (String line : lines) {
            if (line.startsWith("#") || line.startsWith(";"))
                continue;
            if (line.startsWith("[") && line.endsWith("]")) {
                String name = line.substring(1, line.length()-1);
                current = new Section(name);
                sections.put(name, current);
            } else if (line.contains("=")) {
                String[] parts = line.split("=");
                if (parts.length == 2) {
                    current.addValue(parts[0].trim(), replaceEscapees(parts[1].trim()));
                } else if (parts.length > 2) {
                    java.lang.StringBuilder buffer = new java.lang.StringBuilder(parts[1]);
                    for (int i = 2; i!=parts.length; i++) {
                        buffer.append("=");
                        buffer.append(parts[i]);
                    }
                    current.addValue(parts[0].trim(), replaceEscapees(buffer.toString().trim()));
                }
            }
        }
    }
    
    private String replaceEscapees(String value) {
        /*  Sequence
            \\          \ (a single backslash, escaping the escape character)
            \0          Null character
            \a          Bell/Alert/Audible
            \b          Backspace, Bell character for some applications
            \t          Tab character
            \r          Carriage return
            \n          Newline
        */
        String[] parts = value.split("\\\\");
        if (parts.length == 0 || parts.length == 1)
            return value;
        StringBuilder builder = new StringBuilder(parts[0]);
        for (int i=1; i!=parts.length; i++) {
            String part = parts[i];
            if (part.isEmpty()) {
                // replaces "\\" to "\"
                builder.append("\\");
                i++;
            } else {
                char first = part.charAt(0);
                switch (first) {
                    case '0': builder.append("\u0000"); break;
                    case 'a': builder.append("\u0007"); break;
                    case 'b': builder.append("\b"); break;
                    case 't': builder.append("\t"); break;
                    case 'r': builder.append("\r"); break;
                    case 'n': builder.append("\n"); break;
                    default: break;
                }
                builder.append(part.substring(1));
            }
        }
        return builder.toString();
    }
    
    public void load(String file, Charset charset) throws IOException {
        FileInputStream stream = new FileInputStream(file);
        try { load(stream, charset); }
        finally { stream.close(); }
    }
    
    public void load(String file) throws IOException {
        load(file, xowl.utils.Files.detectEncoding(file));
    }
}
